﻿using Microsoft.Graphics.Canvas;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using 纸片人.AttributeUsageFloder;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace 纸片人.PageViews
{
    [LastModified("2022-5-11","create DynamicRipple")]
    [PageTypeAttribute("cpu", "动态水波")]
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class DynamicRipple : Page
    {

        CanvasBitmap originalBitmap;
        CanvasBitmap renderBitmap;
        int imageWidth, imageHeight;
        bool isPause = false;


        Color[] byArrClrInfo;
        //Color[] byArrClrTemp;
        Color[] byArrClrBuff;


        int[] arrWaveTemp;
        Token[] arrToken;


        int[,] m_nArrWaveCurrent;   //当前波形
        int[,] m_nArrWaveNext;      //下一帧的波形



        public DynamicRipple()
        {
            this.InitializeComponent();

            Init();
        }

        private void Init()
        {
            selectPicture.Click += async (s, e) =>
            {
                originalBitmap = await Function.SelectImageAsync();
                imageWidth = (int)originalBitmap.Size.Width;
                imageHeight = (int)originalBitmap.Size.Height;

                m_nArrWaveCurrent = new int[imageWidth, imageHeight];
                m_nArrWaveNext = new int[imageWidth, imageHeight];
                arrWaveTemp = new int[imageWidth * imageHeight];
                arrToken = new Token[imageWidth * imageHeight];
                //设置水波中心点
                SetWavePoint(imageWidth / 2, imageHeight / 2, 5, 5);
            };

            pauseButton.Click += (s, e) =>
           {
               isPause = true;
           };
        }

        public void SetWavePoint(int x, int y, int r, int h)
        {
            //判断波源所在矩形位置是否越出图像 以便将越出部分坐标重置
            int nXStart = x - r < 0 ? 0 : x - r;        //波源矩形位置x轴起点
            int nYStart = y - r < 0 ? 0 : y - r;        //波源矩形位置y轴起点
            int nXLen = x + r >= imageWidth ? imageWidth - 1 : x + r;     //波源x轴矩形长度
            int nYlen = y + r >= imageHeight ? imageHeight - 1 : y + r;   //波源y轴矩形长度
            for (int posX = nXStart; posX < nXLen; posX++)
            {
                for (int posY = nYStart; posY < nYlen; posY++)
                {    //以点(x,y)半径为r内的点赋值一个能量
                    if ((posX - x) * (posX - x) + (posY - y) * (posY - y) < r * r)
                        m_nArrWaveCurrent[posX, posY] = -h;
                    recorToken(posX, posY, 1);

                }
            }
        }

        bool isRipple(int x, int y)
        {
            if ((x <= 0 || y <= 0) || (y >= imageHeight - 1 || x >= imageHeight - 1))
            {
                return false;
            }

            int nNewX = 0, nNewY = 0;
            m_nArrWaveNext[x, y] = ((               //能量传递
                     m_nArrWaveCurrent[x - 1, y] +       //注意 能量传递是通过当前波形计算新的波形
                     m_nArrWaveCurrent[x + 1, y] +       //m_nArrWaveCurrent m_nArrWaveNext 不要弄翻
                     m_nArrWaveCurrent[x, y - 1] +
                     m_nArrWaveCurrent[x, y + 1])
                     >> 1) - m_nArrWaveNext[x, y];


            int t = m_nArrWaveNext[x, y];

            m_nArrWaveNext[x, y] -= m_nArrWaveNext[x, y] >> 5;  //产生阻尼
                                                                //像素偏移 (模拟折射)
            nNewX = ((m_nArrWaveNext[x + 1, y] - m_nArrWaveNext[x - 1, y]) >> 0) + x;   //右移越大 折射变大
            nNewY = ((m_nArrWaveNext[x, y + 1] - m_nArrWaveNext[x, y - 1]) >> 0) + y;   //左移也可 折射变小

            if (nNewX == x && nNewY == y)
            {
                return false;
            }

            replaceColor(nNewX, nNewY, x, y);

            return true;
        }

        void replaceColor(int nNewX, int nNewY, int x, int y)
        {
            if (nNewX < 0) nNewX = -nNewX;              //也可将其赋值为 0
            if (nNewX >= imageHeight) nNewX = imageHeight - 1;
            if (nNewY < 0) nNewY = -nNewY;
            if (nNewY >= imageHeight) nNewY = imageHeight - 1;

            int nIncrement = m_nArrWaveNext[x, y];      //用当前像素点的能量作为光线明暗度变化标志
            nIncrement >>= nIncrement < 0 ? 5 : 3;      //如果负数变暗 正数变量 (适当的位移一下不然差距太大)


            int r = byArrClrInfo[nNewY * imageHeight + nNewX].R + nIncrement;
            int g = byArrClrInfo[nNewY * imageHeight + nNewX].G + nIncrement;
            int b = byArrClrInfo[nNewY * imageHeight + nNewX].B + nIncrement;
            if (nIncrement < 0)
            {       //如果是负数便是变暗 则不能让其越界 0 - 255 
                r = r < 0 ? 0 : r;
                g = g < 0 ? 0 : g;
                b = b < 0 ? 0 : b;


            }
            else
            {
                r = r > 255 ? 255 : r;
                g = g > 255 ? 255 : g;
                b = b > 255 ? 255 : b;


            }
            byArrClrBuff[y * imageHeight + x].R = (byte)r;
            byArrClrBuff[y * imageHeight + x].G = (byte)g;
            byArrClrBuff[y * imageHeight + x].B = (byte)b;
        }

        void recorToken(int x, int y, int isEnable)
        {
            int position = x * imageHeight + y;
            Token t = new Token() { Key = x, Value = y, Position = position, IsEnable = isEnable };
            arrToken[position] = t;
        }

        bool getTokenIsEnable(int x, int y)
        {
            Token token = arrToken[x * imageHeight + y];

            if (token == null || token.IsEnable == 0)
            {
                return false;
            }

            return true;
        }

        void drawTwo()
        {

            int count = 0;
            byArrClrInfo.CopyTo(byArrClrBuff, 0);
            //byArrClrBuff = byArrClrInfo;
            List<IAsyncAction> list = new List<IAsyncAction>();

            List<Token> listTemp = arrToken.Where(p => p != null && p.IsEnable == 1).ToList();

            if (listTemp.Count == 0)
                return;

            int mw = (int)(listTemp.Count - 1) / 20;
            int pw = 0;
            int ph = 0;

            count = listTemp.Count;
            for (int i = 1; i <= 20; i++)
            {
                int sx = pw;
                int sy = ph;
                int ex = mw * i;
                list.Add(Windows.System.Threading.ThreadPool.RunAsync(p =>
                {
                    pool(sx, ex, listTemp);
                }));

                pw = mw * i;
            }

            if ((int)listTemp.Count - 1 % 20 != 0)
            {
                int sx = pw;
                int sy = 0;

                int ex = pw + ((int)listTemp.Count - 1 % 20);


                list.Add(Windows.System.Threading.ThreadPool.RunAsync(p =>
                {
                    pool(sx, ex, listTemp);
                }));
            }

            try
            {
                Task.WaitAll(list.Select(p => p.AsTask()).ToArray());
            }
            catch
            {
                int bb = listTemp.Count;
                int cc = count;
            }

            tb.Text = count + "";

            renderBitmap = CanvasBitmap.CreateFromColors(canvas, byArrClrBuff, imageHeight, imageHeight);

      
            int[,] temp = m_nArrWaveCurrent;
            m_nArrWaveCurrent = m_nArrWaveNext;
            m_nArrWaveNext = temp;
        }

        void pool(int start, int end, List<Token> listTemp)
        {
            //for ( int i  = start;i<end-1;i++)
            //{
            //    var item = listTemp[i];

            //    int x = item.Key;
            //    int y = item.Value;
            //    int position = item.Position;



            //    int ty = y - 1;
            //    int by = y + 1;
            //    int lx = x - 1;
            //    int rx = x + 1;


            //    #region
            //    //上
            //    if (!getTokenIsEnable(x, ty))
            //    {
            //        if (isRipple(x, ty))
            //        {
            //            recorToken(x, ty, 1);
            //        }
            //    }
            //    //左
            //    else if (!getTokenIsEnable(lx, y))
            //    {
            //        if (isRipple(lx, y))
            //        {
            //            recorToken(lx, y, 1);
            //        }
            //    }
            //    //右
            //    else if (!getTokenIsEnable(rx, y))
            //    {
            //        if (isRipple(rx, y))
            //        {

            //            recorToken(rx, y, 1);

            //        }
            //    }
            //    else if (!getTokenIsEnable(x, by))
            //    {
            //        if (isRipple(x, by))
            //        {
            //            recorToken(x, by, 1);

            //        }
            //    }




            //    #endregion

            //    if (!isRipple(x, y))
            //    {
            //        recorToken(x, y, 0);
            //    }
            //    else
            //    {

            //    }
            //}
        }


        private void image_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            double xm = (double)imageHeight / canvas.ActualWidth;
            double ym = (double)imageHeight / canvas.ActualHeight;
            Random rd = new Random();
            Point point = e.GetCurrentPoint((FrameworkElement)sender).Position;
            SetWavePoint((int)(point.X * xm), (int)(point.Y * ym), rd.Next(5, 10), rd.Next(32, 138));
        }
        private void image_Tapped(object sender, TappedRoutedEventArgs e)
        {
            double xm = (double)imageHeight / canvas.ActualWidth;
            double ym = (double)imageHeight / canvas.ActualHeight;


            Random rd = new Random();
            Point point = e.GetPosition((FrameworkElement)sender);
            SetWavePoint((int)(point.X * xm), (int)(point.Y * ym), rd.Next(5, 10), rd.Next(32, 138));
        }


    }
}
